home *** CD-ROM | disk | FTP | other *** search
- /* font.c: define (more or less) format-independent font operations.
-
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "config.h"
-
- #include <ctype.h>
-
- #include "filename.h"
- #include "font.h"
- #include "gf.h"
- #include "list.h"
- #include "pk.h"
- #include "tfm.h"
-
-
- /* We want to allow reading of multiple fonts, so we keep some
- information around for each font we read. */
-
- typedef struct
- {
- bitmap_format_type bitmap_format;
- boolean bitmap_only;
- font_info_type info;
- } internal_font_type;
-
- /* The format of the bitmap file for this font. */
- #define INTERNAL_BITMAP_FORMAT(i) ((i).bitmap_format)
-
- /* If the font was opened with `get_bitmap_font', this field is true;
- if with `get_font', false. */
- #define INTERNAL_BITMAP_ONLY(i) ((i).bitmap_only)
-
- /* The filename for the bitmap font. */
- #define INTERNAL_BITMAP_NAME(i) ((i).bitmap_name)
-
- /* The fontwide information. The parts of this that are found in the
- TFM file are garbage if INTERNAL_BITMAP_ONLY (I) is true. */
- #define INTERNAL_FONT_INFO(i) ((i).info)
-
-
- static void delete_internal_font (string filename);
- static internal_font_type *find_internal_font (string font_name);
- static void save_internal_font (string font_name, internal_font_type);
-
- /* Starting with FONT_NAME as the base filename, e.g., `cmr10', we try
- various extensions to find a PK or GF file at resolution DPI. This
- bitmap font defines the shapes of the characters. */
-
- bitmap_font_type
- get_bitmap_font (string font_name, unsigned dpi)
- {
- bitmap_font_type font;
- internal_font_type internal_f;
- internal_font_type *internal_font_ptr;
- string pk_name, gf_name;
- boolean found_pk = false, found_gf = false;
-
- /* If we are passed a null pointer or the empty string, it's got to be
- a mistake. */
- assert (font_name && *font_name);
-
- /* If we already have the font saved, we just return it, thus (1) saving
- going out to the file system, and (2) causing multiple calls with
- the same FONT_NAME not to open more and more bitmap files. */
- internal_font_ptr = find_internal_font (font_name);
- if (internal_font_ptr != NULL)
- return FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*internal_font_ptr));
-
- pk_name = find_pk_filename (font_name, dpi);
- if (pk_name != NULL)
- { /* Found the PK file, so unless something strange is happening
- (like the file being removed between the `find_path_filename'
- call and the `pk_open_input_file' call), we will be able to
- open it. */
- found_pk = pk_open_input_file (pk_name);
- if (!found_pk)
- FATAL_PERROR (pk_name);
- }
- else if ((gf_name = find_gf_filename (font_name, dpi)) != NULL)
- {
- found_gf = gf_open_input_file (gf_name);
- if (!found_gf)
- {
- perror (gf_name);
- FATAL1 ("(I couldn't find the PK file `%s', either.)", pk_name);
- }
- }
- else
- FATAL2 ("%s.%d{gf,pk}: Nowhere in path", font_name, dpi);
-
-
- /* We've opened the files; get the information we need to return. */
- if (found_pk)
- {
- pk_preamble_type preamble = pk_get_preamble (pk_name);
-
- BITMAP_FONT_DESIGN_SIZE (font)
- = fix_to_real (PK_DESIGN_SIZE (preamble));
- BITMAP_FONT_COMMENT (font) = PK_COMMENT (preamble);
- BITMAP_FONT_CHECKSUM (font) = PK_CHECKSUM (preamble);
- BITMAP_FONT_FILENAME (font) = pk_name;
-
- INTERNAL_BITMAP_FORMAT (internal_f) = pk_format;
- }
- else if (found_gf)
- {
- gf_postamble_type postamble = gf_get_postamble ();
-
- BITMAP_FONT_DESIGN_SIZE (font)
- = fix_to_real (GF_DESIGN_SIZE (postamble));
- BITMAP_FONT_COMMENT (font) = gf_get_preamble ();
- BITMAP_FONT_CHECKSUM (font) = GF_CHECKSUM (postamble);
- BITMAP_FONT_FILENAME (font) = gf_name;
-
- INTERNAL_BITMAP_FORMAT (internal_f) = gf_format;
- }
- else
- FATAL ("No bitmap file found, but I must have found one");
-
- FONT_BITMAP_FONT (INTERNAL_FONT_INFO (internal_f)) = font;
- INTERNAL_BITMAP_ONLY (internal_f) = true;
-
- save_internal_font (font_name, internal_f);
-
- return font;
- }
-
-
- /* Look for both a bitmap font named FONT_NAME, and for the TFM file
- FONT_NAME.tfm. We call `get_bitmap_font' to find the bitmap font.
- For the TFM file, we use the path in the environment variable
- TEXFONTS; if TEXFONTS isn't set, we use the default defined above.
-
- If FONT_NAME was previously opened with `get_bitmap_font', we give a
- fatal error. */
-
- font_info_type
- get_font (string font_name, unsigned dpi)
- {
- unsigned bitmap_checksum;
- font_info_type font;
- internal_font_type internal_f;
- internal_font_type *internal_font_ptr;
- unsigned tfm_checksum;
- string tfm_name;
-
- /* If we are passed a null pointer or the empty string, it's got to be
- a mistake. */
- assert (font_name != NULL && *font_name);
-
- /* If we already have the font saved, we just return it, thus (1) saving
- going out to the file system, and (2) causing multiple calls with
- the same FONT_NAME not to open more and more bitmap files. */
- internal_font_ptr = find_internal_font (font_name);
- if (internal_font_ptr != NULL)
- if (INTERNAL_BITMAP_ONLY (*internal_font_ptr))
- FATAL1 ("get_font: `%s' was opened with get_bitmap_font", font_name);
- else
- return INTERNAL_FONT_INFO (*internal_font_ptr);
-
- /* If we don't have the font saved, we have to look for the TFM file. */
- tfm_name = find_tfm_filename (font_name);
-
- if (tfm_name == NULL)
- FATAL1 ("%s.tfm: Nowhere in path", font_name);
-
- if (!tfm_open_input_file (tfm_name))
- FATAL_PERROR (tfm_name);
-
-
- /* The TFM file is opened. Save some global information. */
- FONT_TFM_FONT (font) = tfm_get_global_info ();
- FONT_TFM_FILENAME (font) = tfm_name;
-
- /* Read the (we hope) corresponding bitmap file. */
- FONT_BITMAP_FONT (font) = get_bitmap_font (font_name, dpi);
-
- /* We have found the bitmap font on the filesystem, so it should be in
- our internal list now. We will overwrite it below. */
- internal_font_ptr = find_internal_font (font_name);
- assert (internal_font_ptr != NULL);
-
- /* We've opened the files; now get the information we're supposed to
- return. */
-
- /* Let's check the checksums. */
- tfm_checksum = tfm_get_checksum ();
- bitmap_checksum = BITMAP_FONT_CHECKSUM (FONT_BITMAP_FONT (font));
-
- if (tfm_checksum != 0 && bitmap_checksum != 0
- && tfm_checksum != bitmap_checksum)
- WARNING1 ("%s: TFM and bitmap checksums don't match", font_name);
-
- INTERNAL_FONT_INFO (internal_f) = font;
- INTERNAL_BITMAP_ONLY (internal_f) = false;
- INTERNAL_BITMAP_FORMAT (internal_f)
- = INTERNAL_BITMAP_FORMAT (*internal_font_ptr);
- save_internal_font (font_name, internal_f);
-
- return font;
- }
-
- /* Close the files we have opened, for tidiness. */
-
- void
- close_font (string font_name)
- {
- internal_font_type *f = find_internal_font (font_name);
-
- if (f == NULL)
- FATAL1 ("close_font: Font `%s' not open", font_name);
-
- switch (INTERNAL_BITMAP_FORMAT (*f))
- {
- case pk_format:
- {
- string pk_name
- = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
- pk_close_input_file (pk_name);
- }
- break;
-
- case gf_format:
- gf_close_input_file ();
- break;
-
- default:
- FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
- }
-
- if (!INTERNAL_BITMAP_ONLY (*f))
- tfm_close_input_file ();
-
- delete_internal_font (font_name);
- }
-
- /* Look for the character numbered CODE in the font FONT_NAME. If it
- doesn't exist, return NULL. Otherwise, fill in a `char_info_type'
- structure and return a pointer to it.
-
- This merely calls the get-a-character routine in the appropriate
- library. */
-
- char_info_type *
- get_char (string font_name, one_byte code)
- {
- char_info_type *c;
- internal_font_type *f = find_internal_font (font_name);
-
- if (f == NULL)
- FATAL1 ("get_char: Font `%s' not open", font_name);
-
- switch (INTERNAL_BITMAP_FORMAT (*f))
- {
- case pk_format:
- {
- string pk_name
- = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
- pk_char_type *pk_char = pk_get_char (code, pk_name);
- if (pk_char == NULL) return NULL;
-
- c = XTALLOC1 (char_info_type);
- CHARCODE (*c) = PK_CHARCODE (*pk_char);
- CHAR_SET_WIDTH (*c) = PK_H_ESCAPEMENT (*pk_char);
- CHAR_TFM_WIDTH (*c) = PK_TFM_WIDTH (*pk_char);
- CHAR_BB (*c) = PK_CHAR_BB (*pk_char);
- CHAR_BITMAP (*c) = PK_BITMAP (*pk_char);
- }
- break;
-
- case gf_format:
- {
- gf_char_type *gf_char = gf_get_char (code);
- if (gf_char == NULL) return NULL;
-
- c = XTALLOC1 (char_info_type);
- CHARCODE (*c) = GF_CHARCODE (*gf_char);
- CHAR_SET_WIDTH (*c) = GF_H_ESCAPEMENT (*gf_char);
- CHAR_TFM_WIDTH (*c) = GF_TFM_WIDTH (*gf_char);
- CHAR_BB (*c) = GF_CHAR_BB (*gf_char);
- CHAR_BITMAP (*c) = GF_BITMAP (*gf_char);
- }
- break;
-
- default:
- FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
- }
-
- return c;
- }
-
- /* Look for the character numbered CODE in the font FONT_NAME. If it
- doesn't exist, return NULL. Otherwise, fill in a `raw_char_type'
- structure and return a pointer to it.
-
- This merely calls the corresponding routine in the appropriate
- library. */
-
- raw_char_type *
- get_raw_char (string font_name, one_byte code)
- {
- raw_char_type *c;
- internal_font_type *f = find_internal_font (font_name);
-
- if (f == NULL)
- FATAL1 ("get_raw_char: Font `%s' not open", font_name);
-
- switch (INTERNAL_BITMAP_FORMAT (*f))
- {
- case pk_format:
- c = NULL;
- break;
-
- case gf_format:
- c = gf_get_raw_char (code);
- break;
-
- default:
- FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
- }
-
- if (c != NULL)
- RAW_CHAR_BITMAP_FORMAT (*c) = INTERNAL_BITMAP_FORMAT (*f);
- return c;
- }
-
-
- /* Free the information in the raw character RAW_CHAR, including the
- character itself. */
-
- void
- free_raw_char (raw_char_type *raw_char)
- {
- free (RAW_CHAR_BYTES (*raw_char));
- free (raw_char);
- }
-
- /* Print the character C to the file F, using ordinary characters. */
-
- void
- print_char (FILE *f, char_info_type c)
- {
- unsigned this_row, this_col;
- bitmap_type b = CHAR_BITMAP (c);
-
- fprintf (f, "Character 0x%x=%u", CHARCODE (c), CHARCODE (c));
- if (isprint (CHARCODE (c)))
- fprintf (f, " (%c)", CHARCODE (c));
-
- fprintf (f, ":\n");
-
- fprintf (f, " min/max col %d/%d, min/max row %d/%d, set width %d.\n",
- CHAR_MIN_COL (c), CHAR_MAX_COL (c),
- CHAR_MIN_ROW (c), CHAR_MAX_ROW (c), CHAR_SET_WIDTH (c));
-
- /* We don't call `print_bitmap' because we want to print the Cartesian
- row number, as well as the bitmap row number. */
-
- for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++)
- {
- for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++)
- putc (BITMAP_PIXEL (b, this_row, this_col) ? '*' : ' ', f);
-
- fprintf (f, "%3d\t%u\n", CHAR_MAX_ROW (c) - this_row, this_row);
- }
- }
-
- /* We want to implement a typical key/value setup: here we are given the
- key (FONT_NAME) and the value (F). We assign an index number to
- FONT_NAME, and store it and F in parallel lists. If we are passed a
- FONT_NAME that is already in the list, we overwrite the old value. */
-
- static list_type font_name_list, internal_font_list;
-
- static void
- save_internal_font (string font_name, internal_font_type f)
- {
- string *new_name;
- internal_font_type *new_font;
- static boolean first_call = true;
-
- if (first_call)
- { /* Have to construct our lists. */
- font_name_list = list_init ();
- internal_font_list = list_init ();
- first_call = false;
- }
-
- new_font = find_internal_font (font_name);
- if (new_font == NULL)
- {
- /* Add another pointer to the end of the lists. */
- new_name = LIST_TAPPEND (&font_name_list, string);
- new_font = LIST_TAPPEND (&internal_font_list, internal_font_type);
-
- /* Save the information. */
- *new_name = xstrdup (font_name);
- }
-
- /* Either update the existing font, or save the new one. */
- *new_font = f;
- }
-
-
- /* This routine returns the font information previously stored with
- FONT_NAME. If FONT_NAME hasn't been saved, we return NULL. */
-
- static internal_font_type *
- find_internal_font (string font_name)
- {
- unsigned e;
-
- for (e = 0; e < LIST_SIZE (font_name_list); e++)
- if (STREQ (*(string *) LIST_ELT (font_name_list, e), font_name))
- return (internal_font_type *) LIST_ELT (internal_font_list, e);
-
- return NULL;
- }
-
-
- /* Remove FILENAME from `font_name_list', by setting the name in
- `font_name_list' to the empty string, so that the element is useless.
- (We don't have any actual memory to free.) What a kludge. */
-
- static void
- delete_internal_font (string filename)
- {
- unsigned e;
-
- /* We can't use `find_internal_font', since we need to know the list
- element index, not just the internal font information. */
- for (e = 0; e < LIST_SIZE (font_name_list); e++)
- if (STREQ (*(string *) LIST_ELT (font_name_list, e), filename))
- {
- string *name = LIST_ELT (font_name_list, e);
- internal_font_type *i
- = (internal_font_type *) LIST_ELT (internal_font_list, e);
-
- free (*name);
- *name = "";
-
- free (i);
-
- return;
- }
-
- FATAL1 ("The font `%s' hasn't been saved", filename);
- }
-